Overview

quick test to see what happens to distribution of env. variables if add more background points (is 10k enough or do I need more)

A note to anyone who might happen to stumble across this… I am a beginner in R and have had no exposure to similar languages. I don’t know what I’m doing. The code herein is unlikely to be elegant and there are probably more efficient ways of running the code.

Built with ‘r getRversion()’.

Package dependencies

You can load them using the following code which uses a function called ipak. Note this function checks to see if the packages are installed first. The “include=FALSE” supresses the package installation text appearing in the document…

load the raw background.csv file with all points to randomly extract points from (../output/env/unique_cell_centroid_lonlat_nafo2_depth.csv)

testbglist <- read.csv("../output/env/unique_cell_centroid_lonlat_nafo2_depth.csv", header = TRUE)
head(testbglist)
backobsno <- nrow(testbglist)
backobsno

the inefficent loop

This loop runs through the netcdf files and then looks for which rows in data_aea it should extract the value to point from, and at what depth (netcDF layer)

Start with 2007_10 data

strt <- Sys.time() #get the start time

xy <- testbglist[ ,c("longitude_","latitude_m")] # This is to tell R where the coordinates are. Note that the column order needs to be longitude, latitude
testbglistsp <- SpatialPointsDataFrame(coords = xy, data = testbglist, proj4string = CRS("+proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs")) # The CRS is used here is for the albers equal area projection.


netcdf_list <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = TRUE) #true means the full path is included
no_netcdf <- length(netcdf_list) #for the loop - need to know how many files to cycle through
netcdf_name <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = FALSE) #false means the path is not included
aea <- raster("../output/env/aea.tif") 
yr <- 2007  # a variable for the observation year
mth <- 10  # a variable for the observation month

for (i in 1:no_netcdf) {  
  print(netcdf_name[i]) #this just prints the name of the netCDF R is working one
  brkyr <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 1)) # extracting the first part of the netcdf filename (which is the year)
  brkmth <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 2)) # extracting the second part of the netcdf filename (which is the month)
  brkvar <- (sapply(strsplit(netcdf_name[i], "_"), "[[", 3)) # extracting the third part of the netcdf (inc.nc)
  temp_brick <- brick(netcdf_list[i], lvar = 4)
  temp_brick <- projectRaster(temp_brick, aea) 
    for (j in 1:nrow(testbglistsp)) {  
      de <- testbglistsp$depthlayerno[[j]]  # a variable for the observation depth layer
          if (brkyr == yr & brkmth == mth & brkvar == "temp.nc"){
              testbglistsp$temp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$temp_depth[j] <- NA
              } else  
                testbglistsp$temp_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "salinity.nc") {
              testbglistsp$salinity_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$salinity_depth[j] <- NA
              } else  
                testbglistsp$salinity_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "chl.nc") {
              testbglistsp$chl_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$chl_depth[j] <- NA
              } else  
                testbglistsp$chl_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "o2.nc") {
              testbglistsp$o2_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$o2_depth[j] <- NA
              } else  
                testbglistsp$o2_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "mlp.nc") {
              testbglistsp$mlp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "ssh.nc") {
              testbglistsp$ssh_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
            
          }
     
    }
}
write.csv(testbglistsp, "../data/env/background_point_check/200710_allbackgroundpoints.csv", row.names = FALSE)
test_back_df <- as.data.frame(testbglistsp)
print(Sys.time()-strt) #time it took to run

ok now create the first lot of random for 2007_10

testbk10000 <- test_back_df[sample(nrow(test_back_df), 10000), ]  #where 10000 = number of rows to sample (large sample as per maxent)
testbk20000 <- test_back_df[sample(nrow(test_back_df), 20000), ]  
testbk50000 <- test_back_df[sample(nrow(test_back_df), 50000), ]  
testbk100000 <- test_back_df[sample(nrow(test_back_df), 100000), ]  
testbk190000 <- test_back_df[sample(nrow(test_back_df), 190000), ]  

plot each variable against the different no of background points

ggplot(testbk10000, aes(x = ssh_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Sea Surface Height Above Geoid (meters)")
dev.copy(png, "../output/env/background_point_check/200710_ssh_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = mlp_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Mixed layer thickness (MLP) (meters)")
dev.copy(png,"../output/env/background_point_check/200710_mlp_back_no.png") # to automatically save the plot to a png AND show it inline 
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = temp_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")  + labs(x = "Temperature at surface (kelvin)")
dev.copy(png,"../output/env/background_point_check/200710_temp_surface_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = temp_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Temperature at sampling depth (kelvin)")
dev.copy(png,"../output/env/background_point_check/200710_temp_depth_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = salinity_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Salinity at surface (kelvin)")
dev.copy(png,"../output/env/background_point_check/200710_salinity_surface_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = salinity_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Salinity at sampling depth (kelvin)")
dev.copy(png,"../output/env/background_point_check/200710_salinity_depth_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = chl_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Chlorophyll concentration at surface (mmol.m-3)")
dev.copy(png,"../output/env/background_point_check/200710_chl_surface_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = chl_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Chlorophyll concentration at sampling depth (mmol.m-3)")
dev.copy(png,"../output/env/background_point_check/200710_chl_depth_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = o2_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Dissolved oxygen concentration at surface (mmol.m-3)")
dev.copy(png,"../output/env/background_point_check/200710_o2_surface_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

ggplot(testbk10000, aes(x = o2_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Dissolved oxygen concentration at sampling depth (mmol.m-3)")
dev.copy(png,"../output/env/background_point_check/200710_o2_depth_back_no.png") # to automatically save the plot to a png AND show it inline
dev.off() # stops automatic saving of the plot to a png

Try again for another month - say 1999 02 AND again 2014 06

This time extract the values for all points and then subset

strt <- Sys.time() #get the start time

xy <- testbglist[ ,c("longitude_","latitude_m")] # This is to tell R where the coordinates are. Note that the column order needs to be longitude, latitude
testbglistsp <- SpatialPointsDataFrame(coords = xy, data = testbglist, proj4string = CRS("+proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs")) # The CRS is used here is for the albers equal area projection.


netcdf_list <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = TRUE) #true means the full path is included
no_netcdf <- length(netcdf_list) #for the loop - need to know how many files to cycle through
netcdf_name <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = FALSE) #false means the path is not included
aea <- raster("../output/env/aea.tif") 
yr <- 1999  # a variable for the observation year
mth <- 02  # a variable for the observation month

for (i in 1:no_netcdf) {  
  print(netcdf_name[i]) #this just prints the name of the netCDF R is working one
  brkyr <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 1)) # extracting the first part of the netcdf filename (which is the year)
  brkmth <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 2)) # extracting the second part of the netcdf filename (which is the month)
  brkvar <- (sapply(strsplit(netcdf_name[i], "_"), "[[", 3)) # extracting the third part of the netcdf (inc.nc)
  temp_brick <- brick(netcdf_list[i], lvar = 4)
  temp_brick <- projectRaster(temp_brick, aea) 
    for (j in 1:nrow(testbglistsp)) {  
      de <- testbglistsp$depthlayerno[[j]]  # a variable for the observation depth layer
          if (brkyr == yr & brkmth == mth & brkvar == "temp.nc"){
              testbglistsp$temp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$temp_depth[j] <- NA
              } else  
                testbglistsp$temp_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "salinity.nc") {
              testbglistsp$salinity_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$salinity_depth[j] <- NA
              } else  
                testbglistsp$salinity_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "chl.nc") {
              testbglistsp$chl_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$chl_depth[j] <- NA
              } else  
                testbglistsp$chl_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "o2.nc") {
              testbglistsp$o2_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$o2_depth[j] <- NA
              } else  
                testbglistsp$o2_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "mlp.nc") {
              testbglistsp$mlp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "ssh.nc") {
              testbglistsp$ssh_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
            
          }
     
    }
}
write.csv(testbglistsp, "../data/env/background_point_check/199902_allbackgroundpoints.csv", row.names = FALSE)
test_back_df <- as.data.frame(testbglistsp)
print(Sys.time()-strt) #time it took to run

ok now create the first lot of random for 1999_02

testbk10000 <- test_back_df[sample(nrow(test_back_df), 10000), ]  #where 10000 = number of rows to sample (large sample as per maxent)
testbk20000 <- test_back_df[sample(nrow(test_back_df), 20000), ]  
testbk50000 <- test_back_df[sample(nrow(test_back_df), 50000), ]  
testbk100000 <- test_back_df[sample(nrow(test_back_df), 100000), ]  
testbk190000 <- test_back_df[sample(nrow(test_back_df), 190000), ]  

and plot

ggplot(testbk10000, aes(x = ssh_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink") + labs(x = "Sea Surface Height Above Geoid (meters)")
dev.copy(png,"../output/env/background_point_check/199902_ssh_back.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

And now 2014_06

strt <- Sys.time() #get the start time

xy <- testbglist[ ,c("longitude_","latitude_m")] # This is to tell R where the coordinates are. Note that the column order needs to be longitude, latitude
testbglistsp <- SpatialPointsDataFrame(coords = xy, data = testbglist, proj4string = CRS("+proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs")) # The CRS is used here is for the albers equal area projection.


netcdf_list <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = TRUE) #true means the full path is included
no_netcdf <- length(netcdf_list) #for the loop - need to know how many files to cycle through
netcdf_name <- list.files("../data/env/bktstncdf", pattern = '*.nc', full.names = FALSE) #false means the path is not included
aea <- raster("../output/env/aea.tif") 
yr <- 2014  # a variable for the observation year
mth <- 06  # a variable for the observation month

for (i in 1:no_netcdf) {  
  print(netcdf_name[i]) #this just prints the name of the netCDF R is working one
  brkyr <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 1)) # extracting the first part of the netcdf filename (which is the year)
  brkmth <- as.integer(sapply(strsplit(netcdf_name[i], "_"), "[[", 2)) # extracting the second part of the netcdf filename (which is the month)
  brkvar <- (sapply(strsplit(netcdf_name[i], "_"), "[[", 3)) # extracting the third part of the netcdf (inc.nc)
  temp_brick <- brick(netcdf_list[i], lvar = 4)
  temp_brick <- projectRaster(temp_brick, aea) 
    for (j in 1:nrow(testbglistsp)) {  
      de <- testbglistsp$depthlayerno[[j]]  # a variable for the observation depth layer
          if (brkyr == yr & brkmth == mth & brkvar == "temp.nc"){
              testbglistsp$temp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$temp_depth[j] <- NA
              } else  
                testbglistsp$temp_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "salinity.nc") {
              testbglistsp$salinity_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$salinity_depth[j] <- NA
              } else  
                testbglistsp$salinity_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "chl.nc") {
              testbglistsp$chl_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$chl_depth[j] <- NA
              } else  
                testbglistsp$chl_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "o2.nc") {
              testbglistsp$o2_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
              if (is.na(de)){
                testbglistsp$o2_depth[j] <- NA
              } else  
                testbglistsp$o2_depth[j] <- extract(x=temp_brick[[de]], y = testbglistsp[j, ]) 
          } else if (brkyr == yr & brkmth == mth & brkvar == "mlp.nc") {
              testbglistsp$mlp_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ])
          } else if (brkyr == yr & brkmth == mth & brkvar == "ssh.nc") {
              testbglistsp$ssh_surface[j] <- extract(x=temp_brick[[1]], y = testbglistsp[j, ]) 
            
          }
     
    }
}
write.csv(testbglistsp, "../data/env/background_point_check/201406_allbackgroundpoints.csv", row.names = FALSE)
test_back_df <- as.data.frame(testbglistsp)
print(Sys.time()-strt) #time it took to run

ok now create the first lot of random for 2014_06

testbk10000 <- test_back_df[sample(nrow(test_back_df), 10000), ]  #where 10000 = number of rows to sample (large sample as per maxent)
testbk20000 <- test_back_df[sample(nrow(test_back_df), 20000), ]  
testbk50000 <- test_back_df[sample(nrow(test_back_df), 50000), ]  
testbk100000 <- test_back_df[sample(nrow(test_back_df), 100000), ]  
testbk190000 <- test_back_df[sample(nrow(test_back_df), 190000), ]  

and plot

ggplot(testbk10000, aes(x = ssh_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_ssh.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = mlp_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_mlp.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = temp_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_temp_surface.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = temp_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_temp_depth.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = salinity_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_salinity_surface.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = salinity_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_salinity_depth.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = chl_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_chl_surface.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = chl_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_chl_depth.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = o2_surface)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_o2_surface.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

ggplot(testbk10000, aes(x = o2_depth)) + geom_density(na.rm = TRUE, colour = "red") + geom_density(data=testbk20000 , na.rm = TRUE, colour = "blue") + geom_density(data=testbk50000 , na.rm = TRUE, colour = "green") + geom_density(data=testbk100000 , na.rm = TRUE, colour = "orange") + geom_density(data=testbk190000 , na.rm = TRUE, colour = "pink")
dev.copy(png,"../output/env/background_point_check/201406_o2_depth.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

3d plot background points

bck2014_06_3d
No trace type specified:
  Based on info supplied, a 'scatter3d' trace seems appropriate.
  Read more about this trace type -> https://plot.ly/r/reference/#scatter3d
No scatter3d mode specifed:
  Setting the mode to markers
  Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
No trace type specified:
  Based on info supplied, a 'scatter3d' trace seems appropriate.
  Read more about this trace type -> https://plot.ly/r/reference/#scatter3d
No scatter3d mode specifed:
  Setting the mode to markers
  Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode

2d plot background points

bck10000points_2d <- plot(x= testbk10000$longitude_, y = testbk10000$latitude_m, xlab = "Longitude (meters)", ylab = "Latitude (meters")
dev.copy(png,"../output/env/background_point_check/bck10000points_2d.png") # to automatically save the plot to a png AND show it inline
png 
  3 
dev.off() # stops automatic saving of the plot to a png
png 
  2 

LS0tDQp0aXRsZTogImJhY2tncm91bmQgcG9pbnRzIC0gaXMgbW9yZSBiZXR0ZXI/Ig0KYXV0aG9yOiAiU2FtYW50aGEgQW5kcmV3cyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KIyBPdmVydmlldw0KcXVpY2sgdGVzdCB0byBzZWUgd2hhdCBoYXBwZW5zIHRvIGRpc3RyaWJ1dGlvbiBvZiBlbnYuIHZhcmlhYmxlcyBpZiBhZGQgbW9yZSBiYWNrZ3JvdW5kIHBvaW50cyAoaXMgMTBrIGVub3VnaCBvciBkbyBJIG5lZWQgbW9yZSkNCg0KQSBub3RlIHRvIGFueW9uZSB3aG8gbWlnaHQgaGFwcGVuIHRvIHN0dW1ibGUgYWNyb3NzIHRoaXMuLi4gSSBhbSBhIGJlZ2lubmVyIGluIFIgYW5kIGhhdmUgaGFkIG5vIGV4cG9zdXJlIHRvIHNpbWlsYXIgbGFuZ3VhZ2VzLiBJIGRvbid0IGtub3cgd2hhdCBJJ20gZG9pbmcuIFRoZSBjb2RlIGhlcmVpbiBpcyB1bmxpa2VseSB0byBiZSBlbGVnYW50IGFuZCB0aGVyZSBhcmUgcHJvYmFibHkgbW9yZSBlZmZpY2llbnQgd2F5cyBvZiBydW5uaW5nIHRoZSBjb2RlLg0KDQpCdWlsdCB3aXRoICdyIGdldFJ2ZXJzaW9uKCknLg0KDQojIFBhY2thZ2UgZGVwZW5kZW5jaWVzDQpZb3UgY2FuIGxvYWQgdGhlbSB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGUgd2hpY2ggdXNlcyBhIGZ1bmN0aW9uIGNhbGxlZCBbaXBha10oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vc3RldmVud29ydGhpbmd0b24vMzE3ODE2MykuIA0KTm90ZSB0aGlzIGZ1bmN0aW9uIGNoZWNrcyB0byBzZWUgaWYgdGhlIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgZmlyc3QuDQpUaGUgImluY2x1ZGU9RkFMU0UiIHN1cHJlc3NlcyB0aGUgcGFja2FnZSBpbnN0YWxsYXRpb24gdGV4dCBhcHBlYXJpbmcgaW4gdGhlIGRvY3VtZW50Li4uDQpgYGB7ciBwcmUtaW5zdGFsbCBwYWNrYWdlcywgaW5jbHVkZT1GQUxTRX0NCnBhY2thZ2VzIDwtIGMoIm5jZGY0IiwgInJhc3RlciIsICJnZ3Bsb3QyIiwgInBsb3RseSIpIA0Kc291cmNlKCIuLi9zcmMvaXBhay5SIikNCmlwYWsocGFja2FnZXMpDQpgYGANCg0KbG9hZCB0aGUgcmF3IGJhY2tncm91bmQuY3N2IGZpbGUgd2l0aCBhbGwgcG9pbnRzIHRvIHJhbmRvbWx5IGV4dHJhY3QgcG9pbnRzIGZyb20gKC4uL291dHB1dC9lbnYvdW5pcXVlX2NlbGxfY2VudHJvaWRfbG9ubGF0X25hZm8yX2RlcHRoLmNzdikNCg0KYGBge3J9DQp0ZXN0YmdsaXN0IDwtIHJlYWQuY3N2KCIuLi9vdXRwdXQvZW52L3VuaXF1ZV9jZWxsX2NlbnRyb2lkX2xvbmxhdF9uYWZvMl9kZXB0aC5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KaGVhZCh0ZXN0YmdsaXN0KQ0KYGBgDQoNCmBgYHtyfQ0KYmFja29ic25vIDwtIG5yb3codGVzdGJnbGlzdCkNCmJhY2tvYnNubw0KYGBgDQoNCg0KDQojIHRoZSBpbmVmZmljZW50IGxvb3ANCg0KDQoNClRoaXMgbG9vcCBydW5zIHRocm91Z2ggdGhlIG5ldGNkZiBmaWxlcyBhbmQgdGhlbiBsb29rcyBmb3Igd2hpY2ggcm93cyBpbiBkYXRhX2FlYSBpdCBzaG91bGQgZXh0cmFjdCB0aGUgdmFsdWUgdG8gcG9pbnQgZnJvbSwgYW5kIGF0IHdoYXQgZGVwdGggKG5ldGNERiBsYXllcikNCg0KU3RhcnQgd2l0aCAyMDA3XzEwIGRhdGENCg0KYGBge3J9DQpzdHJ0IDwtIFN5cy50aW1lKCkgI2dldCB0aGUgc3RhcnQgdGltZQ0KDQp4eSA8LSB0ZXN0YmdsaXN0WyAsYygibG9uZ2l0dWRlXyIsImxhdGl0dWRlX20iKV0gIyBUaGlzIGlzIHRvIHRlbGwgUiB3aGVyZSB0aGUgY29vcmRpbmF0ZXMgYXJlLiBOb3RlIHRoYXQgdGhlIGNvbHVtbiBvcmRlciBuZWVkcyB0byBiZSBsb25naXR1ZGUsIGxhdGl0dWRlDQp0ZXN0YmdsaXN0c3AgPC0gU3BhdGlhbFBvaW50c0RhdGFGcmFtZShjb29yZHMgPSB4eSwgZGF0YSA9IHRlc3RiZ2xpc3QsIHByb2o0c3RyaW5nID0gQ1JTKCIrcHJvaj1hZWEgK2xhdF8xPTUwICtsYXRfMj03MCArbGF0XzA9NDAgK2xvbl8wPS02MCAreF8wPTAgK3lfMD0wICtlbGxwcz1HUlM4MCArZGF0dW09TkFEODMgK3VuaXRzPW0gK25vX2RlZnMiKSkgIyBUaGUgQ1JTIGlzIHVzZWQgaGVyZSBpcyBmb3IgdGhlIGFsYmVycyBlcXVhbCBhcmVhIHByb2plY3Rpb24uDQoNCg0KbmV0Y2RmX2xpc3QgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9lbnYvYmt0c3RuY2RmIiwgcGF0dGVybiA9ICcqLm5jJywgZnVsbC5uYW1lcyA9IFRSVUUpICN0cnVlIG1lYW5zIHRoZSBmdWxsIHBhdGggaXMgaW5jbHVkZWQNCm5vX25ldGNkZiA8LSBsZW5ndGgobmV0Y2RmX2xpc3QpICNmb3IgdGhlIGxvb3AgLSBuZWVkIHRvIGtub3cgaG93IG1hbnkgZmlsZXMgdG8gY3ljbGUgdGhyb3VnaA0KbmV0Y2RmX25hbWUgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9lbnYvYmt0c3RuY2RmIiwgcGF0dGVybiA9ICcqLm5jJywgZnVsbC5uYW1lcyA9IEZBTFNFKSAjZmFsc2UgbWVhbnMgdGhlIHBhdGggaXMgbm90IGluY2x1ZGVkDQphZWEgPC0gcmFzdGVyKCIuLi9vdXRwdXQvZW52L2FlYS50aWYiKSANCnlyIDwtIDIwMDcgICMgYSB2YXJpYWJsZSBmb3IgdGhlIG9ic2VydmF0aW9uIHllYXINCm10aCA8LSAxMCAgIyBhIHZhcmlhYmxlIGZvciB0aGUgb2JzZXJ2YXRpb24gbW9udGgNCg0KZm9yIChpIGluIDE6bm9fbmV0Y2RmKSB7ICANCiAgcHJpbnQobmV0Y2RmX25hbWVbaV0pICN0aGlzIGp1c3QgcHJpbnRzIHRoZSBuYW1lIG9mIHRoZSBuZXRDREYgUiBpcyB3b3JraW5nIG9uZQ0KICBicmt5ciA8LSBhcy5pbnRlZ2VyKHNhcHBseShzdHJzcGxpdChuZXRjZGZfbmFtZVtpXSwgIl8iKSwgIltbIiwgMSkpICMgZXh0cmFjdGluZyB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbmV0Y2RmIGZpbGVuYW1lICh3aGljaCBpcyB0aGUgeWVhcikNCiAgYnJrbXRoIDwtIGFzLmludGVnZXIoc2FwcGx5KHN0cnNwbGl0KG5ldGNkZl9uYW1lW2ldLCAiXyIpLCAiW1siLCAyKSkgIyBleHRyYWN0aW5nIHRoZSBzZWNvbmQgcGFydCBvZiB0aGUgbmV0Y2RmIGZpbGVuYW1lICh3aGljaCBpcyB0aGUgbW9udGgpDQogIGJya3ZhciA8LSAoc2FwcGx5KHN0cnNwbGl0KG5ldGNkZl9uYW1lW2ldLCAiXyIpLCAiW1siLCAzKSkgIyBleHRyYWN0aW5nIHRoZSB0aGlyZCBwYXJ0IG9mIHRoZSBuZXRjZGYgKGluYy5uYykNCiAgdGVtcF9icmljayA8LSBicmljayhuZXRjZGZfbGlzdFtpXSwgbHZhciA9IDQpDQogIHRlbXBfYnJpY2sgPC0gcHJvamVjdFJhc3Rlcih0ZW1wX2JyaWNrLCBhZWEpIA0KICAgIGZvciAoaiBpbiAxOm5yb3codGVzdGJnbGlzdHNwKSkgeyAgDQogICAgICBkZSA8LSB0ZXN0YmdsaXN0c3AkZGVwdGhsYXllcm5vW1tqXV0gICMgYSB2YXJpYWJsZSBmb3IgdGhlIG9ic2VydmF0aW9uIGRlcHRoIGxheWVyDQogICAgICAgICAgaWYgKGJya3lyID09IHlyICYgYnJrbXRoID09IG10aCAmIGJya3ZhciA9PSAidGVtcC5uYyIpew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkdGVtcF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICAgIGlmIChpcy5uYShkZSkpew0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCR0ZW1wX2RlcHRoW2pdIDwtIE5BDQogICAgICAgICAgICAgIH0gZWxzZSAgDQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJHRlbXBfZGVwdGhbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbW2RlXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkNCiAgICAgICAgICB9IGVsc2UgaWYgKGJya3lyID09IHlyICYgYnJrbXRoID09IG10aCAmIGJya3ZhciA9PSAic2FsaW5pdHkubmMiKSB7DQogICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRzYWxpbml0eV9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICAgIGlmIChpcy5uYShkZSkpew0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRzYWxpbml0eV9kZXB0aFtqXSA8LSBOQQ0KICAgICAgICAgICAgICB9IGVsc2UgIA0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRzYWxpbml0eV9kZXB0aFtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbZGVdXSwgeSA9IHRlc3RiZ2xpc3RzcFtqLCBdKSANCiAgICAgICAgICB9IGVsc2UgaWYgKGJya3lyID09IHlyICYgYnJrbXRoID09IG10aCAmIGJya3ZhciA9PSAiY2hsLm5jIikgew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkY2hsX3N1cmZhY2Vbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbWzFdXSwgeSA9IHRlc3RiZ2xpc3RzcFtqLCBdKSANCiAgICAgICAgICAgICAgaWYgKGlzLm5hKGRlKSl7DQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJGNobF9kZXB0aFtqXSA8LSBOQQ0KICAgICAgICAgICAgICB9IGVsc2UgIA0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRjaGxfZGVwdGhbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbW2RlXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gIm8yLm5jIikgew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkbzJfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgICAgICBpZiAoaXMubmEoZGUpKXsNCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkbzJfZGVwdGhbal0gPC0gTkENCiAgICAgICAgICAgICAgfSBlbHNlICANCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkbzJfZGVwdGhbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbW2RlXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gIm1scC5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG1scF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkNCiAgICAgICAgICB9IGVsc2UgaWYgKGJya3lyID09IHlyICYgYnJrbXRoID09IG10aCAmIGJya3ZhciA9PSAic3NoLm5jIikgew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc3NoX3N1cmZhY2Vbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbWzFdXSwgeSA9IHRlc3RiZ2xpc3RzcFtqLCBdKSANCiAgICAgICAgICAgIA0KICAgICAgICAgIH0NCiAgICAgDQogICAgfQ0KfQ0Kd3JpdGUuY3N2KHRlc3RiZ2xpc3RzcCwgIi4uL2RhdGEvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMjAwNzEwX2FsbGJhY2tncm91bmRwb2ludHMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQp0ZXN0X2JhY2tfZGYgPC0gYXMuZGF0YS5mcmFtZSh0ZXN0YmdsaXN0c3ApDQpwcmludChTeXMudGltZSgpLXN0cnQpICN0aW1lIGl0IHRvb2sgdG8gcnVuDQpgYGANCg0Kb2sgbm93IGNyZWF0ZSB0aGUgZmlyc3QgbG90IG9mIHJhbmRvbSBmb3IgMjAwN18xMA0KDQpgYGB7cn0NCnRlc3RiazEwMDAwIDwtIHRlc3RfYmFja19kZltzYW1wbGUobnJvdyh0ZXN0X2JhY2tfZGYpLCAxMDAwMCksIF0gICN3aGVyZSAxMDAwMCA9IG51bWJlciBvZiByb3dzIHRvIHNhbXBsZSAobGFyZ2Ugc2FtcGxlIGFzIHBlciBtYXhlbnQpDQp0ZXN0YmsyMDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMjAwMDApLCBdICANCnRlc3RiazUwMDAwIDwtIHRlc3RfYmFja19kZltzYW1wbGUobnJvdyh0ZXN0X2JhY2tfZGYpLCA1MDAwMCksIF0gIA0KdGVzdGJrMTAwMDAwIDwtIHRlc3RfYmFja19kZltzYW1wbGUobnJvdyh0ZXN0X2JhY2tfZGYpLCAxMDAwMDApLCBdICANCnRlc3RiazE5MDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMTkwMDAwKSwgXSAgDQpgYGANCg0KDQoNCnBsb3QgZWFjaCB2YXJpYWJsZSBhZ2FpbnN0IHRoZSBkaWZmZXJlbnQgbm8gb2YgYmFja2dyb3VuZCBwb2ludHMNCg0KDQoNCmBgYHtyfQ0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IHNzaF9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIlNlYSBTdXJmYWNlIEhlaWdodCBBYm92ZSBHZW9pZCAobWV0ZXJzKSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMjAwNzEwX3NzaF9iYWNrX25vLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gbWxwX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikgKyBsYWJzKHggPSAiTWl4ZWQgbGF5ZXIgdGhpY2tuZXNzIChNTFApIChtZXRlcnMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMDcxMF9tbHBfYmFja19uby5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUgDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSB0ZW1wX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikgICsgbGFicyh4ID0gIlRlbXBlcmF0dXJlIGF0IHN1cmZhY2UgKGtlbHZpbikiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMjAwNzEwX3RlbXBfc3VyZmFjZV9iYWNrX25vLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gdGVtcF9kZXB0aCkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKSArIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBhdCBzYW1wbGluZyBkZXB0aCAoa2VsdmluKSIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDA3MTBfdGVtcF9kZXB0aF9iYWNrX25vLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gc2FsaW5pdHlfc3VyZmFjZSkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKSArIGxhYnMoeCA9ICJTYWxpbml0eSBhdCBzdXJmYWNlIChrZWx2aW4pIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMDcxMF9zYWxpbml0eV9zdXJmYWNlX2JhY2tfbm8ucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBzYWxpbml0eV9kZXB0aCkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKSArIGxhYnMoeCA9ICJTYWxpbml0eSBhdCBzYW1wbGluZyBkZXB0aCAoa2VsdmluKSIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDA3MTBfc2FsaW5pdHlfZGVwdGhfYmFja19uby5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IGNobF9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIkNobG9yb3BoeWxsIGNvbmNlbnRyYXRpb24gYXQgc3VyZmFjZSAobW1vbC5tLTMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMDcxMF9jaGxfc3VyZmFjZV9iYWNrX25vLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gY2hsX2RlcHRoKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIkNobG9yb3BoeWxsIGNvbmNlbnRyYXRpb24gYXQgc2FtcGxpbmcgZGVwdGggKG1tb2wubS0zKSIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDA3MTBfY2hsX2RlcHRoX2JhY2tfbm8ucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBvMl9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIkRpc3NvbHZlZCBveHlnZW4gY29uY2VudHJhdGlvbiBhdCBzdXJmYWNlIChtbW9sLm0tMykiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMjAwNzEwX28yX3N1cmZhY2VfYmFja19uby5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IG8yX2RlcHRoKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIkRpc3NvbHZlZCBveHlnZW4gY29uY2VudHJhdGlvbiBhdCBzYW1wbGluZyBkZXB0aCAobW1vbC5tLTMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMDcxMF9vMl9kZXB0aF9iYWNrX25vLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KYGBgDQoNClRyeSBhZ2FpbiBmb3IgYW5vdGhlciBtb250aCAtIHNheSAxOTk5IDAyIEFORCBhZ2FpbiAyMDE0IDA2DQoNClRoaXMgdGltZSBleHRyYWN0IHRoZSB2YWx1ZXMgZm9yIGFsbCBwb2ludHMgYW5kIHRoZW4gc3Vic2V0DQoNCmBgYHtyfQ0Kc3RydCA8LSBTeXMudGltZSgpICNnZXQgdGhlIHN0YXJ0IHRpbWUNCg0KeHkgPC0gdGVzdGJnbGlzdFsgLGMoImxvbmdpdHVkZV8iLCJsYXRpdHVkZV9tIildICMgVGhpcyBpcyB0byB0ZWxsIFIgd2hlcmUgdGhlIGNvb3JkaW5hdGVzIGFyZS4gTm90ZSB0aGF0IHRoZSBjb2x1bW4gb3JkZXIgbmVlZHMgdG8gYmUgbG9uZ2l0dWRlLCBsYXRpdHVkZQ0KdGVzdGJnbGlzdHNwIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoY29vcmRzID0geHksIGRhdGEgPSB0ZXN0YmdsaXN0LCBwcm9qNHN0cmluZyA9IENSUygiK3Byb2o9YWVhICtsYXRfMT01MCArbGF0XzI9NzAgK2xhdF8wPTQwICtsb25fMD0tNjAgK3hfMD0wICt5XzA9MCArZWxscHM9R1JTODAgK2RhdHVtPU5BRDgzICt1bml0cz1tICtub19kZWZzIikpICMgVGhlIENSUyBpcyB1c2VkIGhlcmUgaXMgZm9yIHRoZSBhbGJlcnMgZXF1YWwgYXJlYSBwcm9qZWN0aW9uLg0KDQoNCm5ldGNkZl9saXN0IDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvZW52L2JrdHN0bmNkZiIsIHBhdHRlcm4gPSAnKi5uYycsIGZ1bGwubmFtZXMgPSBUUlVFKSAjdHJ1ZSBtZWFucyB0aGUgZnVsbCBwYXRoIGlzIGluY2x1ZGVkDQpub19uZXRjZGYgPC0gbGVuZ3RoKG5ldGNkZl9saXN0KSAjZm9yIHRoZSBsb29wIC0gbmVlZCB0byBrbm93IGhvdyBtYW55IGZpbGVzIHRvIGN5Y2xlIHRocm91Z2gNCm5ldGNkZl9uYW1lIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvZW52L2JrdHN0bmNkZiIsIHBhdHRlcm4gPSAnKi5uYycsIGZ1bGwubmFtZXMgPSBGQUxTRSkgI2ZhbHNlIG1lYW5zIHRoZSBwYXRoIGlzIG5vdCBpbmNsdWRlZA0KYWVhIDwtIHJhc3RlcigiLi4vb3V0cHV0L2Vudi9hZWEudGlmIikgDQp5ciA8LSAxOTk5ICAjIGEgdmFyaWFibGUgZm9yIHRoZSBvYnNlcnZhdGlvbiB5ZWFyDQptdGggPC0gMDIgICMgYSB2YXJpYWJsZSBmb3IgdGhlIG9ic2VydmF0aW9uIG1vbnRoDQoNCmZvciAoaSBpbiAxOm5vX25ldGNkZikgeyAgDQogIHByaW50KG5ldGNkZl9uYW1lW2ldKSAjdGhpcyBqdXN0IHByaW50cyB0aGUgbmFtZSBvZiB0aGUgbmV0Q0RGIFIgaXMgd29ya2luZyBvbmUNCiAgYnJreXIgPC0gYXMuaW50ZWdlcihzYXBwbHkoc3Ryc3BsaXQobmV0Y2RmX25hbWVbaV0sICJfIiksICJbWyIsIDEpKSAjIGV4dHJhY3RpbmcgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG5ldGNkZiBmaWxlbmFtZSAod2hpY2ggaXMgdGhlIHllYXIpDQogIGJya210aCA8LSBhcy5pbnRlZ2VyKHNhcHBseShzdHJzcGxpdChuZXRjZGZfbmFtZVtpXSwgIl8iKSwgIltbIiwgMikpICMgZXh0cmFjdGluZyB0aGUgc2Vjb25kIHBhcnQgb2YgdGhlIG5ldGNkZiBmaWxlbmFtZSAod2hpY2ggaXMgdGhlIG1vbnRoKQ0KICBicmt2YXIgPC0gKHNhcHBseShzdHJzcGxpdChuZXRjZGZfbmFtZVtpXSwgIl8iKSwgIltbIiwgMykpICMgZXh0cmFjdGluZyB0aGUgdGhpcmQgcGFydCBvZiB0aGUgbmV0Y2RmIChpbmMubmMpDQogIHRlbXBfYnJpY2sgPC0gYnJpY2sobmV0Y2RmX2xpc3RbaV0sIGx2YXIgPSA0KQ0KICB0ZW1wX2JyaWNrIDwtIHByb2plY3RSYXN0ZXIodGVtcF9icmljaywgYWVhKSANCiAgICBmb3IgKGogaW4gMTpucm93KHRlc3RiZ2xpc3RzcCkpIHsgIA0KICAgICAgZGUgPC0gdGVzdGJnbGlzdHNwJGRlcHRobGF5ZXJub1tbal1dICAjIGEgdmFyaWFibGUgZm9yIHRoZSBvYnNlcnZhdGlvbiBkZXB0aCBsYXllcg0KICAgICAgICAgIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInRlbXAubmMiKXsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJHRlbXBfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgICAgICBpZiAoaXMubmEoZGUpKXsNCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkdGVtcF9kZXB0aFtqXSA8LSBOQQ0KICAgICAgICAgICAgICB9IGVsc2UgIA0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCR0ZW1wX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInNhbGluaXR5Lm5jIikgew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgICAgICBpZiAoaXMubmEoZGUpKXsNCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfZGVwdGhbal0gPC0gTkENCiAgICAgICAgICAgICAgfSBlbHNlICANCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfZGVwdGhbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbW2RlXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gImNobC5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJGNobF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICAgIGlmIChpcy5uYShkZSkpew0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRjaGxfZGVwdGhbal0gPC0gTkENCiAgICAgICAgICAgICAgfSBlbHNlICANCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkY2hsX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgIH0gZWxzZSBpZiAoYnJreXIgPT0geXIgJiBicmttdGggPT0gbXRoICYgYnJrdmFyID09ICJvMi5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX3N1cmZhY2Vbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbWzFdXSwgeSA9IHRlc3RiZ2xpc3RzcFtqLCBdKSANCiAgICAgICAgICAgICAgaWYgKGlzLm5hKGRlKSl7DQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX2RlcHRoW2pdIDwtIE5BDQogICAgICAgICAgICAgIH0gZWxzZSAgDQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgIH0gZWxzZSBpZiAoYnJreXIgPT0geXIgJiBicmttdGggPT0gbXRoICYgYnJrdmFyID09ICJtbHAubmMiKSB7DQogICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRtbHBfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInNzaC5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJHNzaF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICANCiAgICAgICAgICB9DQogICAgIA0KICAgIH0NCn0NCndyaXRlLmNzdih0ZXN0YmdsaXN0c3AsICIuLi9kYXRhL2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl9hbGxiYWNrZ3JvdW5kcG9pbnRzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KdGVzdF9iYWNrX2RmIDwtIGFzLmRhdGEuZnJhbWUodGVzdGJnbGlzdHNwKQ0KcHJpbnQoU3lzLnRpbWUoKS1zdHJ0KSAjdGltZSBpdCB0b29rIHRvIHJ1bg0KYGBgDQoNCm9rIG5vdyBjcmVhdGUgdGhlIGZpcnN0IGxvdCBvZiByYW5kb20gZm9yIDE5OTlfMDINCg0KYGBge3J9DQp0ZXN0YmsxMDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMTAwMDApLCBdICAjd2hlcmUgMTAwMDAgPSBudW1iZXIgb2Ygcm93cyB0byBzYW1wbGUgKGxhcmdlIHNhbXBsZSBhcyBwZXIgbWF4ZW50KQ0KdGVzdGJrMjAwMDAgPC0gdGVzdF9iYWNrX2RmW3NhbXBsZShucm93KHRlc3RfYmFja19kZiksIDIwMDAwKSwgXSAgDQp0ZXN0Yms1MDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgNTAwMDApLCBdICANCnRlc3RiazEwMDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMTAwMDAwKSwgXSAgDQp0ZXN0YmsxOTAwMDAgPC0gdGVzdF9iYWNrX2RmW3NhbXBsZShucm93KHRlc3RfYmFja19kZiksIDE5MDAwMCksIF0gIA0KYGBgDQoNCmFuZCBwbG90DQoNCg0KYGBge3J9DQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gc3NoX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikgKyBsYWJzKHggPSAiU2VhIFN1cmZhY2UgSGVpZ2h0IEFib3ZlIEdlb2lkIChtZXRlcnMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl9zc2hfYmFjay5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IG1scF9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICArIGxhYnMoeCA9ICJNaXhlZCBsYXllciB0aGlja25lc3MgKE1MUCkgKG1ldGVycykiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMTk5OTAyX21scC5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IHRlbXBfc3VyZmFjZSkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKSArIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBhdCBzdXJmYWNlIChrZWx2aW4pIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl90ZW1wX3N1cmZhY2UucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSB0ZW1wX2RlcHRoKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICsgbGFicyh4ID0gIlRlbXBlcmF0dXJlIGF0IHNhbXBsaW5nIGRlcHRoIChrZWx2aW4pIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl90ZW1wX2RlcHRoLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gc2FsaW5pdHlfc3VyZmFjZSkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMTk5OTAyX3NhbGluaXR5X3N1cmZhY2UucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBzYWxpbml0eV9kZXB0aCkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMTk5OTAyX3NhbGluaXR5X2RlcHRoLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gY2hsX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl9jaGxfc3VyZmFjZS5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IGNobF9kZXB0aCkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAxOTk5ICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl9jaGxfZGVwdGgucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBvMl9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwMTk5OSAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKQ0KZGV2LmNvcHkocG5nLCIuLi9vdXRwdXQvZW52L2JhY2tncm91bmRfcG9pbnRfY2hlY2svMTk5OTAyX28yX3N1cmZhY2UucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBvMl9kZXB0aCkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMDE5OTkgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzE5OTkwMl9vMl9kZXB0aC5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCmBgYA0KDQoNCkFuZCBub3cgMjAxNF8wNg0KDQoNCmBgYHtyfQ0Kc3RydCA8LSBTeXMudGltZSgpICNnZXQgdGhlIHN0YXJ0IHRpbWUNCg0KeHkgPC0gdGVzdGJnbGlzdFsgLGMoImxvbmdpdHVkZV8iLCJsYXRpdHVkZV9tIildICMgVGhpcyBpcyB0byB0ZWxsIFIgd2hlcmUgdGhlIGNvb3JkaW5hdGVzIGFyZS4gTm90ZSB0aGF0IHRoZSBjb2x1bW4gb3JkZXIgbmVlZHMgdG8gYmUgbG9uZ2l0dWRlLCBsYXRpdHVkZQ0KdGVzdGJnbGlzdHNwIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoY29vcmRzID0geHksIGRhdGEgPSB0ZXN0YmdsaXN0LCBwcm9qNHN0cmluZyA9IENSUygiK3Byb2o9YWVhICtsYXRfMT01MCArbGF0XzI9NzAgK2xhdF8wPTQwICtsb25fMD0tNjAgK3hfMD0wICt5XzA9MCArZWxscHM9R1JTODAgK2RhdHVtPU5BRDgzICt1bml0cz1tICtub19kZWZzIikpICMgVGhlIENSUyBpcyB1c2VkIGhlcmUgaXMgZm9yIHRoZSBhbGJlcnMgZXF1YWwgYXJlYSBwcm9qZWN0aW9uLg0KDQoNCm5ldGNkZl9saXN0IDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvZW52L2JrdHN0bmNkZiIsIHBhdHRlcm4gPSAnKi5uYycsIGZ1bGwubmFtZXMgPSBUUlVFKSAjdHJ1ZSBtZWFucyB0aGUgZnVsbCBwYXRoIGlzIGluY2x1ZGVkDQpub19uZXRjZGYgPC0gbGVuZ3RoKG5ldGNkZl9saXN0KSAjZm9yIHRoZSBsb29wIC0gbmVlZCB0byBrbm93IGhvdyBtYW55IGZpbGVzIHRvIGN5Y2xlIHRocm91Z2gNCm5ldGNkZl9uYW1lIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvZW52L2JrdHN0bmNkZiIsIHBhdHRlcm4gPSAnKi5uYycsIGZ1bGwubmFtZXMgPSBGQUxTRSkgI2ZhbHNlIG1lYW5zIHRoZSBwYXRoIGlzIG5vdCBpbmNsdWRlZA0KYWVhIDwtIHJhc3RlcigiLi4vb3V0cHV0L2Vudi9hZWEudGlmIikgDQp5ciA8LSAyMDE0ICAjIGEgdmFyaWFibGUgZm9yIHRoZSBvYnNlcnZhdGlvbiB5ZWFyDQptdGggPC0gMDYgICMgYSB2YXJpYWJsZSBmb3IgdGhlIG9ic2VydmF0aW9uIG1vbnRoDQoNCmZvciAoaSBpbiAxOm5vX25ldGNkZikgeyAgDQogIHByaW50KG5ldGNkZl9uYW1lW2ldKSAjdGhpcyBqdXN0IHByaW50cyB0aGUgbmFtZSBvZiB0aGUgbmV0Q0RGIFIgaXMgd29ya2luZyBvbmUNCiAgYnJreXIgPC0gYXMuaW50ZWdlcihzYXBwbHkoc3Ryc3BsaXQobmV0Y2RmX25hbWVbaV0sICJfIiksICJbWyIsIDEpKSAjIGV4dHJhY3RpbmcgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG5ldGNkZiBmaWxlbmFtZSAod2hpY2ggaXMgdGhlIHllYXIpDQogIGJya210aCA8LSBhcy5pbnRlZ2VyKHNhcHBseShzdHJzcGxpdChuZXRjZGZfbmFtZVtpXSwgIl8iKSwgIltbIiwgMikpICMgZXh0cmFjdGluZyB0aGUgc2Vjb25kIHBhcnQgb2YgdGhlIG5ldGNkZiBmaWxlbmFtZSAod2hpY2ggaXMgdGhlIG1vbnRoKQ0KICBicmt2YXIgPC0gKHNhcHBseShzdHJzcGxpdChuZXRjZGZfbmFtZVtpXSwgIl8iKSwgIltbIiwgMykpICMgZXh0cmFjdGluZyB0aGUgdGhpcmQgcGFydCBvZiB0aGUgbmV0Y2RmIChpbmMubmMpDQogIHRlbXBfYnJpY2sgPC0gYnJpY2sobmV0Y2RmX2xpc3RbaV0sIGx2YXIgPSA0KQ0KICB0ZW1wX2JyaWNrIDwtIHByb2plY3RSYXN0ZXIodGVtcF9icmljaywgYWVhKSANCiAgICBmb3IgKGogaW4gMTpucm93KHRlc3RiZ2xpc3RzcCkpIHsgIA0KICAgICAgZGUgPC0gdGVzdGJnbGlzdHNwJGRlcHRobGF5ZXJub1tbal1dICAjIGEgdmFyaWFibGUgZm9yIHRoZSBvYnNlcnZhdGlvbiBkZXB0aCBsYXllcg0KICAgICAgICAgIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInRlbXAubmMiKXsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJHRlbXBfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgICAgICBpZiAoaXMubmEoZGUpKXsNCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkdGVtcF9kZXB0aFtqXSA8LSBOQQ0KICAgICAgICAgICAgICB9IGVsc2UgIA0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCR0ZW1wX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInNhbGluaXR5Lm5jIikgew0KICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgICAgICBpZiAoaXMubmEoZGUpKXsNCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfZGVwdGhbal0gPC0gTkENCiAgICAgICAgICAgICAgfSBlbHNlICANCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3Akc2FsaW5pdHlfZGVwdGhbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbW2RlXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gImNobC5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJGNobF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICAgIGlmIChpcy5uYShkZSkpew0KICAgICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRjaGxfZGVwdGhbal0gPC0gTkENCiAgICAgICAgICAgICAgfSBlbHNlICANCiAgICAgICAgICAgICAgICB0ZXN0YmdsaXN0c3AkY2hsX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgIH0gZWxzZSBpZiAoYnJreXIgPT0geXIgJiBicmttdGggPT0gbXRoICYgYnJrdmFyID09ICJvMi5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX3N1cmZhY2Vbal0gPC0gZXh0cmFjdCh4PXRlbXBfYnJpY2tbWzFdXSwgeSA9IHRlc3RiZ2xpc3RzcFtqLCBdKSANCiAgICAgICAgICAgICAgaWYgKGlzLm5hKGRlKSl7DQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX2RlcHRoW2pdIDwtIE5BDQogICAgICAgICAgICAgIH0gZWxzZSAgDQogICAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJG8yX2RlcHRoW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1tkZV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pIA0KICAgICAgICAgIH0gZWxzZSBpZiAoYnJreXIgPT0geXIgJiBicmttdGggPT0gbXRoICYgYnJrdmFyID09ICJtbHAubmMiKSB7DQogICAgICAgICAgICAgIHRlc3RiZ2xpc3RzcCRtbHBfc3VyZmFjZVtqXSA8LSBleHRyYWN0KHg9dGVtcF9icmlja1tbMV1dLCB5ID0gdGVzdGJnbGlzdHNwW2osIF0pDQogICAgICAgICAgfSBlbHNlIGlmIChicmt5ciA9PSB5ciAmIGJya210aCA9PSBtdGggJiBicmt2YXIgPT0gInNzaC5uYyIpIHsNCiAgICAgICAgICAgICAgdGVzdGJnbGlzdHNwJHNzaF9zdXJmYWNlW2pdIDwtIGV4dHJhY3QoeD10ZW1wX2JyaWNrW1sxXV0sIHkgPSB0ZXN0YmdsaXN0c3BbaiwgXSkgDQogICAgICAgICAgICANCiAgICAgICAgICB9DQogICAgIA0KICAgIH0NCn0NCndyaXRlLmNzdih0ZXN0YmdsaXN0c3AsICIuLi9kYXRhL2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9hbGxiYWNrZ3JvdW5kcG9pbnRzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KdGVzdF9iYWNrX2RmIDwtIGFzLmRhdGEuZnJhbWUodGVzdGJnbGlzdHNwKQ0KcHJpbnQoU3lzLnRpbWUoKS1zdHJ0KSAjdGltZSBpdCB0b29rIHRvIHJ1bg0KYGBgDQoNCm9rIG5vdyBjcmVhdGUgdGhlIGZpcnN0IGxvdCBvZiByYW5kb20gZm9yIDIwMTRfMDYNCg0KYGBge3J9DQp0ZXN0YmsxMDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMTAwMDApLCBdICAjd2hlcmUgMTAwMDAgPSBudW1iZXIgb2Ygcm93cyB0byBzYW1wbGUgKGxhcmdlIHNhbXBsZSBhcyBwZXIgbWF4ZW50KQ0KdGVzdGJrMjAwMDAgPC0gdGVzdF9iYWNrX2RmW3NhbXBsZShucm93KHRlc3RfYmFja19kZiksIDIwMDAwKSwgXSAgDQp0ZXN0Yms1MDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgNTAwMDApLCBdICANCnRlc3RiazEwMDAwMCA8LSB0ZXN0X2JhY2tfZGZbc2FtcGxlKG5yb3codGVzdF9iYWNrX2RmKSwgMTAwMDAwKSwgXSAgDQp0ZXN0YmsxOTAwMDAgPC0gdGVzdF9iYWNrX2RmW3NhbXBsZShucm93KHRlc3RfYmFja19kZiksIDE5MDAwMCksIF0gIA0KYGBgDQoNCmFuZCBwbG90DQoNCg0KYGBge3J9DQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gc3NoX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikgKyBsYWJzKHggPSAiU2VhIFN1cmZhY2UgSGVpZ2h0IEFib3ZlIEdlb2lkIChtZXRlcnMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9zc2gucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBtbHBfc3VyZmFjZSkpICsgZ2VvbV9kZW5zaXR5KG5hLnJtID0gVFJVRSwgY29sb3VyID0gInJlZCIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMjAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJibHVlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0Yms1MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImdyZWVuIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxMDAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJvcmFuZ2UiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazE5MDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gInBpbmsiKSAgKyBsYWJzKHggPSAiTWl4ZWQgbGF5ZXIgdGhpY2tuZXNzIChNTFApIChtZXRlcnMpIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9tbHAucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSB0ZW1wX3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikrIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBhdCBzdXJmYWNlIChrZWx2aW4pIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl90ZW1wX3N1cmZhY2UucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSB0ZW1wX2RlcHRoKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpICArIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBhdCBzYW1wbGluZyBkZXB0aCAoa2VsdmluKSIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDE0MDZfdGVtcF9kZXB0aC5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IHNhbGluaXR5X3N1cmZhY2UpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9zYWxpbml0eV9zdXJmYWNlLnBuZyIpICMgdG8gYXV0b21hdGljYWxseSBzYXZlIHRoZSBwbG90IHRvIGEgcG5nIEFORCBzaG93IGl0IGlubGluZQ0KZGV2Lm9mZigpICMgc3RvcHMgYXV0b21hdGljIHNhdmluZyBvZiB0aGUgcGxvdCB0byBhIHBuZw0KDQpnZ3Bsb3QodGVzdGJrMTAwMDAsIGFlcyh4ID0gc2FsaW5pdHlfZGVwdGgpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9zYWxpbml0eV9kZXB0aC5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IGNobF9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDE0MDZfY2hsX3N1cmZhY2UucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBjaGxfZGVwdGgpKSArIGdlb21fZGVuc2l0eShuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJyZWQiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazIwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiYmx1ZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrNTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJncmVlbiIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTAwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAib3JhbmdlIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsxOTAwMDAgLCBuYS5ybSA9IFRSVUUsIGNvbG91ciA9ICJwaW5rIikNCmRldi5jb3B5KHBuZywiLi4vb3V0cHV0L2Vudi9iYWNrZ3JvdW5kX3BvaW50X2NoZWNrLzIwMTQwNl9jaGxfZGVwdGgucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQoNCmdncGxvdCh0ZXN0YmsxMDAwMCwgYWVzKHggPSBvMl9zdXJmYWNlKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDE0MDZfbzJfc3VyZmFjZS5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCg0KZ2dwbG90KHRlc3RiazEwMDAwLCBhZXMoeCA9IG8yX2RlcHRoKSkgKyBnZW9tX2RlbnNpdHkobmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicmVkIikgKyBnZW9tX2RlbnNpdHkoZGF0YT10ZXN0YmsyMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gImJsdWUiKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazUwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAiZ3JlZW4iKSArIGdlb21fZGVuc2l0eShkYXRhPXRlc3RiazEwMDAwMCAsIG5hLnJtID0gVFJVRSwgY29sb3VyID0gIm9yYW5nZSIpICsgZ2VvbV9kZW5zaXR5KGRhdGE9dGVzdGJrMTkwMDAwICwgbmEucm0gPSBUUlVFLCBjb2xvdXIgPSAicGluayIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay8yMDE0MDZfbzJfZGVwdGgucG5nIikgIyB0byBhdXRvbWF0aWNhbGx5IHNhdmUgdGhlIHBsb3QgdG8gYSBwbmcgQU5EIHNob3cgaXQgaW5saW5lDQpkZXYub2ZmKCkgIyBzdG9wcyBhdXRvbWF0aWMgc2F2aW5nIG9mIHRoZSBwbG90IHRvIGEgcG5nDQpgYGANCg0KDQoNCiMgM2QgcGxvdCBiYWNrZ3JvdW5kIHBvaW50cw0KDQpgYGB7cn0NCmJjazIwMTRfMDZfM2QgPC0gcGxvdF9seSh4PSB0ZXN0YmsxMDAwMCRsb25naXR1ZGVfLCB5ID0gdGVzdGJrMTAwMDAkbGF0aXR1ZGVfbSwgeiA9IHRlc3RiazEwMDAwJGRlcHRobGF5ZXJubykNCmJjazIwMTRfMDZfM2QNCmBgYA0KDQojIDJkIHBsb3QgYmFja2dyb3VuZCBwb2ludHMNCg0KYGBge3J9DQpiY2sxMDAwMHBvaW50c18yZCA8LSBwbG90KHg9IHRlc3RiazEwMDAwJGxvbmdpdHVkZV8sIHkgPSB0ZXN0YmsxMDAwMCRsYXRpdHVkZV9tLCB4bGFiID0gIkxvbmdpdHVkZSAobWV0ZXJzKSIsIHlsYWIgPSAiTGF0aXR1ZGUgKG1ldGVycyIpDQpkZXYuY29weShwbmcsIi4uL291dHB1dC9lbnYvYmFja2dyb3VuZF9wb2ludF9jaGVjay9iY2sxMDAwMHBvaW50c18yZC5wbmciKSAjIHRvIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgcGxvdCB0byBhIHBuZyBBTkQgc2hvdyBpdCBpbmxpbmUNCmRldi5vZmYoKSAjIHN0b3BzIGF1dG9tYXRpYyBzYXZpbmcgb2YgdGhlIHBsb3QgdG8gYSBwbmcNCmBgYA==